home *** CD-ROM | disk | FTP | other *** search
/ Saar AMOK 2 / Saar AMOK II - Oktober 1994 (1994)(Kreativ Marketing)(DE)[!][I-7598].iso / disks / 651_700 / 662 / playcdda / play.c < prev    next >
C/C++ Source or Header  |  1994-01-04  |  34KB  |  1,298 lines

  1. /* play.c: */
  2.  
  3. #include "includes.h"
  4.  
  5. #define VERSION "1.1 (04.01.1994)"
  6.  
  7. #define HRDBLBF
  8.  
  9. #define CDDA_BUFSIZE 2368
  10. #define SUBCHANNEL_SIZE 16
  11. #define STD_BUFSIZE 2048
  12. #define SENSE_LENGTH 32
  13. #define AUDIO_BUFSIZE ((CDDA_BUFSIZE-SUBCHANNEL_SIZE)/g_compression_factor/4)
  14. #define TOTAL_CDDA_BUFSIZE (g_buffers*2*CDDA_BUFSIZE)
  15. #define TOTAL_AUDIO_BUFSIZE (g_buffers*2*AUDIO_BUFSIZE)
  16. #define CDDA_STD_BUFSIZE (STD_BUFSIZE+SENSE_LENGTH)
  17.  
  18. typedef short t_bool;
  19.  
  20. typedef struct toc {
  21.   char reserved1;
  22.   unsigned char flags;
  23.   unsigned char track_number;
  24.   char reserved2;
  25.   long address;
  26. } t_toc;
  27.  
  28. typedef enum dtype {UNKNOWNDRIVE = 0, TOSHIBA, APPLECD300} t_drivetype;
  29.  
  30. static char *TheVersion = "$VER: PlayCDDA " VERSION;
  31.  
  32. t_bool g_called_from_cli;
  33. char g_scsi_device[80];
  34. t_drivetype g_whatdrive = UNKNOWNDRIVE;
  35. int g_scsi_id;
  36. LONG g_memory_type = MEMF_CHIP;
  37. UBYTE *g_cdda_base = NULL;
  38. UBYTE *g_audio_base = NULL;
  39. UBYTE *g_std_buf_base = NULL;
  40. UBYTE *g_cdda_buf[2];
  41. UBYTE *g_cdda_std_buf;
  42. UBYTE *g_audio_buf[2];
  43. struct MsgPort *g_cdda_port = NULL;
  44. struct MsgPort *g_audio_port[2] = { NULL, NULL };
  45. ULONG g_cdda_sigmask;
  46. ULONG g_audio_sigmask[2];
  47. #ifndef HRDBLBF
  48. struct IOStdReq *g_scsireq = NULL;
  49. t_bool g_outstanding_cdda_request = FALSE;
  50. struct SCSICmd *g_scsicmd = NULL;
  51. UBYTE *g_sense_data;
  52. #else
  53. struct IOStdReq *g_scsireq[2] = {NULL, NULL};
  54. t_bool g_outstanding_cdda_request[2] = {FALSE, FALSE};
  55. struct SCSICmd *g_scsicmd[2] = {NULL, NULL};
  56. UBYTE *g_sense_data[2];
  57. #endif
  58. struct IOAudio *g_audioreq[2] = { NULL, NULL };
  59. t_bool g_audio_device_open = FALSE;
  60. long g_period;
  61. int g_toc_length;
  62. t_toc g_toc[100];
  63. short g_volume = 1;
  64. /* possible values for g_compression_factor: 2, 3, 4, 6, 7, 12, 14, 28, 49 */
  65. unsigned short g_compression_factor = 2;
  66. unsigned short g_buffers = 4;
  67.  
  68. /* user interface variables: */
  69.  
  70. #ifdef __SASC
  71. extern struct Library *DOSBase;
  72. #endif
  73. struct Library *IconBase = NULL;
  74. struct Library *IntuitionBase = NULL;
  75. struct Library *GadToolsBase = NULL;
  76. struct GfxBase *GfxBase = NULL;
  77. struct Screen *g_screen = NULL;
  78. void *g_visual_info = NULL;
  79. struct Window *g_window = NULL;
  80. struct Gadget *g_glist = NULL;
  81. t_bool g_bye = FALSE;
  82. char g_track_str[3] = { 0, 0, 0 };
  83. char g_index_str[3] = { 0, 0, 0 };
  84. char g_time_str[6] = { 0, 0, ':', 0, 0, 0 };
  85. unsigned char g_track, g_index;
  86. unsigned char g_minute, g_seconds;
  87.  
  88. enum gadget_ids {
  89.   GID_SAMPLING_RATE = 21,
  90.   GID_BUFFERS,
  91.   GID_VOLUME,
  92.   GID_PREV,
  93.   GID_NEXT,
  94.   GID_START,
  95.   GID_STOP,
  96.   GID_TRACK,
  97.   GID_INDEX,
  98.   GID_TIME,
  99.  
  100.   /* always last: */
  101.   GID_MAX
  102. };
  103.  
  104. struct Gadget *g_gadgets[GID_MAX];
  105.  
  106. #ifdef __SASC
  107. void __regargs __chkabort(void)
  108. {
  109. }
  110. #endif
  111.  
  112. void Cleanup_User_Interface (void)
  113. {
  114.   if (g_window)
  115.     CloseWindow (g_window);
  116.   if (g_glist)
  117.     FreeGadgets (g_glist);
  118.   if (g_visual_info)
  119.     FreeVisualInfo (g_visual_info);
  120.   if (g_screen)
  121.     UnlockPubScreen (NULL, g_screen);
  122.   if (GfxBase)
  123.     CloseLibrary ((struct Library *) GfxBase);
  124.   if (GadToolsBase)
  125.     CloseLibrary (GadToolsBase);
  126.   if (IntuitionBase)
  127.     CloseLibrary (IntuitionBase);
  128. }
  129.  
  130. void Cleanup_Audio (void)
  131. {
  132.   if (g_cdda_base) {
  133.     FreeMem (g_cdda_base, TOTAL_CDDA_BUFSIZE + 15);
  134.     g_cdda_base = NULL;
  135.   }
  136.   if (g_audio_base) {
  137.     FreeMem (g_audio_base, TOTAL_AUDIO_BUFSIZE + 15);
  138.     g_audio_base = NULL;
  139.   }
  140.   if (g_audio_device_open) {
  141.     CloseDevice ((struct IORequest *) g_audioreq[0]);
  142.     g_audio_device_open = FALSE;
  143.   }
  144.   if (g_audio_port[0]) {
  145.     DeleteMsgPort (g_audio_port[0]);
  146.     g_audio_port[0] = NULL;
  147.   }
  148.   if (g_audio_port[1]) {
  149.     DeleteMsgPort (g_audio_port[1]);
  150.     g_audio_port[1] = NULL;
  151.   }
  152.   if (g_audioreq[0]) {
  153.     FreeMem (g_audioreq[0], sizeof (struct IOAudio));
  154.     g_audioreq[0] = NULL;
  155.   }
  156.   if (g_audioreq[1]) {
  157.     FreeMem (g_audioreq[1], sizeof (struct IOAudio));
  158.     g_audioreq[1] = NULL;
  159.   }
  160. }
  161.  
  162. void Cleanup (void)
  163. {
  164. #ifdef HRDBLBF
  165.   int i;
  166. #endif
  167.  
  168.   Cleanup_Audio ();
  169.  
  170.   if (g_std_buf_base)
  171.     FreeMem (g_std_buf_base, CDDA_STD_BUFSIZE + 15);
  172. #ifndef HRDBLBF
  173.   if (g_scsicmd)
  174.     FreeMem (g_scsicmd, sizeof (struct SCSICmd));
  175.   if (g_scsireq) {
  176.     if (g_scsireq->io_Device) {
  177.       if (g_outstanding_cdda_request) {
  178.         AbortIO ((struct IORequest *) g_scsireq);
  179.         WaitIO ((struct IORequest *) g_scsireq);
  180.       }
  181.       CloseDevice ((struct IORequest *) g_scsireq);
  182.     }
  183.     DeleteIORequest ((struct IORequest *) g_scsireq);
  184.   }
  185. #else
  186.   for (i = 0; i < 2; i++) {
  187.     if (g_scsicmd[i])
  188.       FreeMem (g_scsicmd[i], sizeof (struct SCSICmd));
  189.     if (g_scsireq[i]) {
  190.       if (g_scsireq[i]->io_Device) {
  191.     if (g_outstanding_cdda_request[i]) {
  192.       AbortIO ((struct IORequest *) g_scsireq[i]);
  193.       WaitIO ((struct IORequest *) g_scsireq[i]);
  194.     }
  195.     CloseDevice ((struct IORequest *) g_scsireq[i]);
  196.       }
  197.       DeleteIORequest ((struct IORequest *) g_scsireq[i]);
  198.     }
  199.   }
  200. #endif
  201.   if (g_cdda_port)
  202.     DeleteMsgPort (g_cdda_port);
  203.  
  204.   Cleanup_User_Interface ();
  205.   
  206.   if (IconBase)
  207.     CloseLibrary (IconBase);
  208. }
  209.  
  210. void Fatal_Error (char *p_message, ...)
  211. {
  212.   va_list arg;
  213.  
  214.   static struct EasyStruct req = {
  215.     sizeof (struct EasyStruct),
  216.     0,
  217.     (UBYTE *) "PlayCDDA Error",
  218.     NULL,
  219.     (UBYTE *) "Abort"
  220.   };
  221.  
  222.   va_start (arg, p_message);
  223.   if (IntuitionBase) {
  224.     req.es_TextFormat = (UBYTE *) p_message;
  225.     EasyRequestArgs (NULL, &req, NULL, arg);
  226.   } else if (g_called_from_cli) {
  227.     VPrintf ((UBYTE *) p_message, (LONG *) arg);
  228.     WriteChars ((UBYTE *) "\n", 1);
  229.   } else
  230.     Alert (0x0000CDDA);
  231.  
  232.   va_end (p_message);
  233.  
  234.   exit (1);
  235. }
  236.  
  237. char *Open_User_Interface (void)
  238. {
  239.   static struct TextAttr Topaz8 = { (UBYTE *) "topaz.font", 8, 0, 0, };
  240.   struct TextFont *font;
  241.   int i, j;
  242.   static char *labels[20] = {
  243.     "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11",
  244.     "12", "13", "14", "15", "16", "17", "18", "19", "20"
  245.   };
  246.   static char *sampling_rate_labels[] = {
  247.     "22050 bps",  /* 2 */
  248.     "14700 bps",  /* 3 */
  249.     "11025 bps",  /* 4 */
  250.     "7350 bps",   /* 6 */
  251.     "6300 bps",   /* 7 */
  252.     NULL
  253.   };
  254.   static char *buffers_labels[] = {
  255.     "2",
  256.     "4",
  257.     "8",
  258.     "16",
  259.     "32",
  260.     "64",
  261.     NULL
  262.   };
  263.   static char *volume_labels[] = {
  264.     "Low",
  265.     "Medium",
  266.     "High",
  267.     NULL
  268.   };
  269.   struct NewGadget ng;
  270.   struct Gadget *gad;
  271.   int topborder;
  272.  
  273.   if (!(IntuitionBase = OpenLibrary ((UBYTE *) "intuition.library", 37)))
  274.     return "cannot open intuition.library";
  275.   if (!(GadToolsBase = OpenLibrary ((UBYTE *) "gadtools.library", 37)))
  276.     return "cannot open gadtools.library";
  277.   if (!(GfxBase = (struct GfxBase *)
  278.       OpenLibrary ((UBYTE *) "graphics.library", 37)))
  279.     return "cannot open graphics.library";
  280.  
  281.   /* does the font exist? */
  282.   if (!(font = OpenFont (&Topaz8)))
  283.     return "cannot open topaz 8 font";
  284.   CloseFont (font);
  285.  
  286.   if (!(g_screen = LockPubScreen (NULL)))
  287.     return "cannot lock default public screen";
  288.  
  289.   if (!(g_visual_info = GetVisualInfo (g_screen, TAG_END)))
  290.     return "GetVisualInfo() failed";
  291.  
  292.   gad = CreateContext (&g_glist);
  293.  
  294.   topborder = g_screen->WBorTop + (g_screen->Font->ta_YSize + 1);
  295.  
  296.   ng.ng_Width = 20;
  297.   ng.ng_Height = 12;
  298.   ng.ng_TextAttr = &Topaz8;
  299.   ng.ng_VisualInfo = g_visual_info;
  300.   ng.ng_Flags = 0;
  301.  
  302.   for (i=0; i<5; i++)
  303.     for (j=0; j<4; j++) {
  304.       ng.ng_GadgetText = (UBYTE *) labels[i*4+j];
  305.       ng.ng_GadgetID = i*4 + j + 1;
  306.       ng.ng_LeftEdge = 10 + j * 24;
  307.       ng.ng_TopEdge = topborder + 2 + i * 16;
  308.       g_gadgets[ng.ng_GadgetID] = gad =
  309.         CreateGadget (BUTTON_KIND, gad, &ng,
  310.           GA_Disabled, TRUE,
  311.           TAG_END);
  312.     }
  313.  
  314.   ng.ng_GadgetID = GID_PREV;
  315.   ng.ng_GadgetText = (UBYTE *) "Prev";
  316.   ng.ng_Width = 44;
  317.   ng.ng_LeftEdge = 10;
  318.   ng.ng_TopEdge = topborder + 2 + 5 * 16;
  319.   g_gadgets[ng.ng_GadgetID] =
  320.     gad = CreateGadget (BUTTON_KIND, gad, &ng, TAG_END);
  321.   
  322.   ng.ng_GadgetID = GID_NEXT;
  323.   ng.ng_GadgetText = (UBYTE *) "Next";
  324.   ng.ng_LeftEdge = 58;
  325.   g_gadgets[ng.ng_GadgetID] =
  326.     gad = CreateGadget (BUTTON_KIND, gad, &ng, TAG_END);
  327.  
  328.   ng.ng_GadgetID = GID_START;
  329.   ng.ng_GadgetText = (UBYTE *) "Start";
  330.   ng.ng_LeftEdge = 120;
  331.   ng.ng_TopEdge = topborder + 2 + 4 * 16;
  332.   ng.ng_Width = 120;
  333.   ng.ng_Height = 28;
  334.   g_gadgets[ng.ng_GadgetID] =
  335.     gad = CreateGadget (BUTTON_KIND, gad, &ng, TAG_END);
  336.  
  337.   ng.ng_GadgetID = GID_STOP;
  338.   ng.ng_GadgetText = (UBYTE *) "Stop";
  339.   ng.ng_LeftEdge = 250;
  340.   g_gadgets[ng.ng_GadgetID] =
  341.     gad = CreateGadget (BUTTON_KIND, gad, &ng, TAG_END);
  342.  
  343.   ng.ng_GadgetText = (UBYTE *) "Sampling rate:";
  344.   ng.ng_GadgetID = GID_SAMPLING_RATE;
  345.   ng.ng_Width = 120;
  346.   ng.ng_Height = 12;
  347.   ng.ng_LeftEdge = 250;
  348.   ng.ng_TopEdge = topborder + 2;
  349.   g_gadgets[ng.ng_GadgetID] =
  350.     gad = CreateGadget (CYCLE_KIND, gad, &ng,
  351.       GTCY_Labels, sampling_rate_labels,
  352.       TAG_END);
  353.  
  354.   ng.ng_GadgetText = (UBYTE *) "Buffers:      ";
  355.   ng.ng_TopEdge += 16;
  356.   ng.ng_GadgetID = GID_BUFFERS;
  357.   g_gadgets[ng.ng_GadgetID] =
  358.     gad = CreateGadget (CYCLE_KIND, gad, &ng,
  359.       GTCY_Labels, buffers_labels,
  360.       GTCY_Active, 1,
  361.       TAG_END);
  362.  
  363.   ng.ng_GadgetText = (UBYTE *) "Volume:       ";
  364.   ng.ng_TopEdge += 16;
  365.   ng.ng_GadgetID = GID_VOLUME;
  366.   g_gadgets[ng.ng_GadgetID] =
  367.     gad = CreateGadget (CYCLE_KIND, gad, &ng,
  368.       GTCY_Labels, volume_labels,
  369.       GTCY_Active, (int) g_volume-1,
  370.       TAG_END);
  371.  
  372.   ng.ng_GadgetID = GID_TRACK;
  373.   ng.ng_GadgetText = (UBYTE *) "Track";
  374.   ng.ng_Width = 25;
  375.   ng.ng_Height = 12;
  376.   ng.ng_LeftEdge = 170;
  377.   ng.ng_TopEdge = topborder + 2 + 3 * 16;
  378.   g_gadgets[ng.ng_GadgetID] =
  379.     gad = CreateGadget (TEXT_KIND, gad, &ng,
  380.       GTTX_Border, TRUE,
  381.       TAG_END);
  382.  
  383.   ng.ng_GadgetID = GID_INDEX;
  384.   ng.ng_GadgetText = (UBYTE *) "Index";
  385.   ng.ng_LeftEdge = 250;
  386.   g_gadgets[ng.ng_GadgetID] =
  387.     gad = CreateGadget (TEXT_KIND, gad, &ng,
  388.       GTTX_Border, TRUE,
  389.       TAG_END);
  390.   
  391.   ng.ng_GadgetID = GID_TIME;
  392.   ng.ng_GadgetText = (UBYTE *) "Time";
  393.   ng.ng_Width = 50;
  394.   ng.ng_LeftEdge = 320;
  395.   g_gadgets[ng.ng_GadgetID] =
  396.     gad = CreateGadget (TEXT_KIND, gad, &ng,
  397.       GTTX_Border, TRUE,
  398.       TAG_END);
  399.   
  400.  
  401.   if (!gad)
  402.     return "cannot create gadgets";
  403.  
  404.   g_window = OpenWindowTags (NULL,
  405.     WA_Title, TheVersion + 6,
  406.     WA_Gadgets, g_glist,
  407.     WA_Left, 20,
  408.     WA_Top, 20,
  409.     WA_Width, 385,
  410.     WA_Height, topborder + 98,
  411.     WA_IDCMP, IDCMP_CLOSEWINDOW | BUTTONIDCMP | CYCLEIDCMP,
  412.     WA_PubScreen, g_screen,
  413.     WA_DragBar, TRUE,
  414.     WA_DepthGadget, TRUE,
  415.     WA_CloseGadget, TRUE,
  416.     WA_Activate, TRUE,
  417.     WA_SmartRefresh, TRUE,
  418.     TAG_END);
  419.   if (!g_window)
  420.     return "cannot open window";
  421.  
  422.   return NULL;
  423. }
  424.  
  425. void Alloc_Audio (void)
  426. {
  427.   static UBYTE whichannel[] = { 1, 2, 4, 8 };
  428.   int i;
  429.  
  430.   /* allocate buffers: */
  431.  
  432.   g_audio_base = AllocMem (TOTAL_AUDIO_BUFSIZE + 15, MEMF_PUBLIC | MEMF_CHIP);
  433.   if (!g_audio_base)
  434.     Fatal_Error ("cannot allocate memory");
  435.  
  436.   g_cdda_base = AllocMem (TOTAL_CDDA_BUFSIZE + 15, MEMF_PUBLIC | g_memory_type);
  437.   if (!g_cdda_base)
  438.     Fatal_Error ("cannot allocate memory");
  439.  
  440.   /* make the buffers quad-word aligned. This greatly helps 
  441.    * performance on '040-powered systems with DMA SCSI
  442.    * controllers.
  443.    */
  444.   g_cdda_buf[0] = (UBYTE *)(((long) g_cdda_base + 15) & ~15);
  445.   g_audio_buf[0] = (UBYTE *)(((long) g_audio_base + 15) & ~15);
  446.  
  447.   g_cdda_buf[1] = g_cdda_buf[0] + g_buffers * CDDA_BUFSIZE;  
  448.   g_audio_buf[1] = g_audio_buf[0] + g_buffers * AUDIO_BUFSIZE;
  449.  
  450.   /* allocate message ports and IO requests: */
  451.  
  452.   if (!(g_audio_port[0] = CreateMsgPort ()) || 
  453.       !(g_audio_port[1] = CreateMsgPort ()))
  454.     Fatal_Error ("cannot allocate message ports");
  455.  
  456.   g_audio_sigmask[0] = (1 << g_audio_port[0]->mp_SigBit);
  457.   g_audio_sigmask[1] = (1 << g_audio_port[1]->mp_SigBit);
  458.  
  459.   if (!(g_audioreq[0] = AllocMem (sizeof (struct IOAudio),
  460.                         MEMF_PUBLIC | MEMF_CLEAR)) ||
  461.       !(g_audioreq[1] = AllocMem (sizeof (struct IOAudio),
  462.                         MEMF_PUBLIC | MEMF_CLEAR)))
  463.     Fatal_Error ("cannot allocate memory");
  464.  
  465.   /* open audio device: */
  466.  
  467.   g_audioreq[0]->ioa_Request.io_Message.mn_ReplyPort = g_audio_port[0];
  468.   g_audioreq[0]->ioa_Request.io_Message.mn_Node.ln_Pri = 0;
  469.   g_audioreq[0]->ioa_Request.io_Command = ADCMD_ALLOCATE;
  470.   g_audioreq[0]->ioa_Request.io_Flags = ADIOF_NOWAIT;
  471.   g_audioreq[0]->ioa_AllocKey = 0;
  472.   g_audioreq[0]->ioa_Data = whichannel;
  473.   g_audioreq[0]->ioa_Length = sizeof (whichannel);
  474.  
  475.   if (OpenDevice ((UBYTE *) AUDIONAME, 0,
  476.             (struct IORequest *) g_audioreq[0], 0))
  477.     Fatal_Error ("cannot open audio.device\n");
  478.  
  479.   g_audio_device_open = TRUE;
  480.  
  481.   *(g_audioreq[1]) = *(g_audioreq[0]);
  482.   g_audioreq[0]->ioa_Request.io_Message.mn_ReplyPort = g_audio_port[0];
  483.   g_audioreq[1]->ioa_Request.io_Message.mn_ReplyPort = g_audio_port[1];
  484.   g_audioreq[0]->ioa_Data = (UBYTE *) g_audio_buf[0];
  485.   g_audioreq[1]->ioa_Data = (UBYTE *) g_audio_buf[1];
  486.  
  487.   for (i=0; i<2; i++) {
  488.     struct IOAudio *req = g_audioreq[i];
  489.  
  490.     req->ioa_Request.io_Command = CMD_WRITE;
  491.     req->ioa_Request.io_Flags = ADIOF_PERVOL;
  492.     req->ioa_Length = g_buffers * AUDIO_BUFSIZE;
  493.     req->ioa_Period = g_period;
  494.     req->ioa_Volume = 64;
  495.     req->ioa_Cycles = 1;
  496.   }
  497. }
  498.  
  499. void Alloc_CDROM (void)
  500. {
  501. #ifdef HRDBLBF
  502.   int i;
  503. #endif
  504.  
  505.   g_std_buf_base = AllocMem (CDDA_STD_BUFSIZE + 15, MEMF_PUBLIC | MEMF_CHIP);
  506.   if (!g_std_buf_base)
  507.     Fatal_Error ("cannot allocate memory");
  508.  
  509. #ifndef HRDBLBF
  510.   g_scsicmd = AllocMem (sizeof (struct SCSICmd), MEMF_PUBLIC | MEMF_CHIP);
  511.   if (!g_scsicmd)
  512.     Fatal_Error ("cannot allocate memory");
  513. #else
  514.   for (i = 0; i < 2; i++) {
  515.     g_scsicmd[i] = AllocMem (sizeof (struct SCSICmd), MEMF_PUBLIC | MEMF_CHIP);
  516.     if (!g_scsicmd[i])
  517.       Fatal_Error ("cannot allocate memory");
  518.   }
  519. #endif
  520.  
  521.   /* make the buffer quad-word aligned. This greatly helps 
  522.    * performance on '040-powered systems with DMA SCSI
  523.    * controllers.
  524.    */
  525.  
  526.   g_cdda_std_buf = (UBYTE *)(((long) g_std_buf_base + 15) & ~15);
  527. #ifndef HRDBLBF
  528.   g_sense_data = g_cdda_std_buf + STD_BUFSIZE;
  529. #else
  530.   for (i = 0; i < 2; i++)
  531.     g_sense_data[i] = g_cdda_std_buf + STD_BUFSIZE;
  532. #endif
  533.   
  534.   /* allocate message ports and IO requests: */
  535.  
  536.   if (!(g_cdda_port = CreateMsgPort ()))
  537.     Fatal_Error ("cannot allocate message port");
  538.  
  539.   g_cdda_sigmask = (1 << g_cdda_port->mp_SigBit);
  540.  
  541. #ifndef HRDBLBF
  542.   if (!(g_scsireq = CreateIORequest (g_cdda_port,
  543.                         sizeof (struct IOStdReq))))
  544.     Fatal_Error ("cannot create IO request\n");
  545.  
  546.   /* open SCSI device: */
  547.  
  548.   g_scsireq->io_Device = NULL;
  549.  
  550.   if (OpenDevice ((UBYTE *) g_scsi_device, g_scsi_id,
  551.             (struct IORequest *) g_scsireq, 0)) {
  552.     if (g_called_from_cli)
  553.       Fatal_Error ("Cannot open \"%s\", unit %ld",
  554.                  g_scsi_device, g_scsi_id);
  555.     else
  556.       Fatal_Error ("Cannot open \"%s\", unit %ld\n"
  557.                  "Please edit the tooltype entries\n"
  558.            "in the PlayCDDA icon!",
  559.                  g_scsi_device, g_scsi_id);
  560.   }
  561. #else
  562.   for (i = 0; i < 2; i++) {
  563.     if (!(g_scsireq[i] = CreateIORequest (g_cdda_port,
  564.                        sizeof (struct IOStdReq))))
  565.       Fatal_Error ("cannot create IO request\n");
  566.  
  567.     /* open SCSI device: */
  568.  
  569.     g_scsireq[i]->io_Device = NULL;
  570.  
  571.     if (OpenDevice ((UBYTE *) g_scsi_device, g_scsi_id,
  572.             (struct IORequest *) g_scsireq[i], 0)) {
  573.       if (g_called_from_cli)
  574.     Fatal_Error ("Cannot open \"%s\", unit %ld",
  575.              g_scsi_device, g_scsi_id);
  576.       else
  577.     Fatal_Error ("Cannot open \"%s\", unit %ld\n"
  578.              "Please edit the tooltype entries\n"
  579.              "in the PlayCDDA icon!",
  580.              g_scsi_device, g_scsi_id);
  581.     }
  582.   }
  583. #endif
  584.  
  585. }
  586.  
  587. void Do_SCSI_Command (UBYTE *p_command, int p_length,
  588.              short p_phase, int p_sync, int p_direction)
  589. {
  590. #ifndef HRDBLBF
  591.   g_scsireq->io_Length   = sizeof (struct SCSICmd);
  592.   g_scsireq->io_Data     = (APTR) g_scsicmd;
  593.   g_scsireq->io_Command  = HD_SCSICMD;
  594.  
  595.   if (p_phase == -1) {
  596.     g_scsicmd->scsi_Data        = (UWORD *) g_cdda_std_buf;
  597.     g_scsicmd->scsi_Length      = STD_BUFSIZE;
  598.   } else {
  599.     g_scsicmd->scsi_Data        = (UWORD *) g_cdda_buf[p_phase];
  600.     g_scsicmd->scsi_Length      = g_buffers * CDDA_BUFSIZE;
  601.   }
  602.  
  603.   g_scsicmd->scsi_Flags       = SCSIF_AUTOSENSE | p_direction;
  604.   g_scsicmd->scsi_SenseData   = (UBYTE *) g_sense_data;
  605.   g_scsicmd->scsi_SenseLength = SENSE_LENGTH;
  606.   g_scsicmd->scsi_SenseActual = 0;
  607.   g_scsicmd->scsi_Command     = (UBYTE *) p_command;
  608.   g_scsicmd->scsi_CmdLength   = p_length;
  609.  
  610.   if (p_sync) {
  611.     int i = 0;
  612.     
  613.     do {
  614.       DoIO ((struct IORequest *) g_scsireq);
  615.       if (g_scsicmd->scsi_Status == 0)
  616.         return;
  617.       i++;
  618.     } while (i < 2);
  619.     Fatal_Error ("sync SCSI command failed");
  620.   } else {
  621.     SendIO ((struct IORequest *) g_scsireq);
  622.     g_outstanding_cdda_request = TRUE;
  623.   }
  624. #else
  625.   if (p_phase == -1) {
  626.     p_phase = 0;
  627.     g_scsicmd[p_phase]->scsi_Data        = (UWORD *) g_cdda_std_buf;
  628.     g_scsicmd[p_phase]->scsi_Length      = STD_BUFSIZE;
  629.   } else {
  630.     g_scsicmd[p_phase]->scsi_Data        = (UWORD *) g_cdda_buf[p_phase];
  631.     g_scsicmd[p_phase]->scsi_Length      = g_buffers * CDDA_BUFSIZE;
  632.   }
  633.   g_scsireq[p_phase]->io_Length   = sizeof (struct SCSICmd);
  634.   g_scsireq[p_phase]->io_Data     = (APTR) g_scsicmd[p_phase];
  635.   g_scsireq[p_phase]->io_Command  = HD_SCSICMD;
  636.  
  637.   g_scsicmd[p_phase]->scsi_Flags       = SCSIF_AUTOSENSE | p_direction;
  638.   g_scsicmd[p_phase]->scsi_SenseData   = (UBYTE *) g_sense_data[p_phase];
  639.   g_scsicmd[p_phase]->scsi_SenseLength = SENSE_LENGTH;
  640.   g_scsicmd[p_phase]->scsi_SenseActual = 0;
  641.   g_scsicmd[p_phase]->scsi_Command     = (UBYTE *) p_command;
  642.   g_scsicmd[p_phase]->scsi_CmdLength   = p_length;
  643.  
  644.   if (p_sync) {
  645.     int i = 0;
  646.     
  647.     do {
  648.       DoIO ((struct IORequest *) g_scsireq[p_phase]);
  649.       if (g_scsicmd[p_phase]->scsi_Status == 0)
  650.         return;
  651.       i++;
  652.     } while (i < 2);
  653.     Fatal_Error ("sync SCSI command failed");
  654.   } else {
  655.     SendIO ((struct IORequest *) g_scsireq[p_phase]);
  656.     g_outstanding_cdda_request[p_phase] = TRUE;
  657.   }
  658. #endif
  659. }
  660.  
  661. #ifndef HRDBLBF
  662. void Wait_CDROM_Command (void)
  663. #else
  664. void Wait_CDROM_Command (short p_phase)
  665. #endif     
  666. {
  667.   ULONG sig;
  668.  
  669. #ifndef HRDBLBF  
  670.   sig = Wait (SIGBREAKF_CTRL_C | g_cdda_sigmask);
  671.   if (sig & g_cdda_sigmask) {
  672.     if (CheckIO ((struct IORequest *) g_scsireq)) {
  673.       WaitIO ((struct IORequest *) g_scsireq);
  674.       g_outstanding_cdda_request = FALSE;
  675.       if (g_scsicmd->scsi_Status)
  676.         Fatal_Error ("async SCSI command failed");
  677.     }
  678.   }
  679.   if (sig & SIGBREAKF_CTRL_C)
  680.     exit (1);
  681. #else
  682.   /* HR */
  683.  
  684.   if (p_phase < 0 || p_phase > 1)
  685.     Fatal_Error ("wrong p_phase argument for Wait_CDROM_Command");
  686.  
  687.   if (g_outstanding_cdda_request[p_phase] != FALSE) {
  688.     for (;;) {
  689.       sig = Wait (SIGBREAKF_CTRL_C | g_cdda_sigmask);
  690.       if (sig & g_cdda_sigmask) {
  691.     if (CheckIO ((struct IORequest *) g_scsireq[p_phase])) {
  692.       WaitIO ((struct IORequest *) g_scsireq[p_phase]);
  693.       g_outstanding_cdda_request[p_phase] = FALSE;
  694.       if (g_scsicmd[p_phase]->scsi_Status)
  695.         Do_SCSI_Command (g_scsicmd[p_phase]->scsi_Command,
  696.                  g_scsicmd[p_phase]->scsi_CmdLength,
  697.                  p_phase, FALSE, SCSIF_READ);
  698.       else
  699.         break;
  700.     }
  701.       }
  702.       if (sig & SIGBREAKF_CTRL_C)
  703.     exit (1);
  704.     }
  705.   }
  706. #endif
  707. }
  708.  
  709. void Start_CDROM_Read (short p_phase, long p_sector)
  710. {
  711.   static UBYTE cmd[2][12] =
  712.     {
  713.       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
  714.       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}
  715.     };
  716.  
  717.   if (p_phase < 0 || p_phase > 1)
  718.     Fatal_Error ("Invalid p_phase argument for Start_CDROM_Read()");
  719.  
  720.   cmd[p_phase][2] = (p_sector >> 24);
  721.   cmd[p_phase][3] = ((p_sector >> 16) & 0xFF);
  722.   cmd[p_phase][4] = ((p_sector >> 8) & 0xFF);
  723.   cmd[p_phase][5] = (p_sector & 0xFF);
  724.  
  725.   if (g_whatdrive == APPLECD300) {
  726.     cmd[p_phase][0] = 0xD8;
  727.     cmd[p_phase][9] = g_buffers;
  728.     Do_SCSI_Command (cmd[p_phase], 12, p_phase, FALSE, SCSIF_READ);
  729.   }
  730.   else if (g_whatdrive == TOSHIBA) {
  731.     cmd[p_phase][0] = 0x28;
  732.     cmd[p_phase][8] = g_buffers;
  733.     Do_SCSI_Command (cmd[p_phase], 10, p_phase, FALSE, SCSIF_READ);
  734.   }
  735. }
  736.  
  737. #ifndef HRDBLBF
  738. void Wait_CDROM_Read (void)
  739. {
  740.   Wait_CDROM_Command ();
  741. }
  742. #else
  743. void Wait_CDROM_Read (short p_phase)
  744. {
  745.   Wait_CDROM_Command (p_phase);
  746. }
  747. #endif
  748.  
  749. void Update_Track_Data (short p_num)
  750. {
  751.   g_track_str[0] = '0' + (p_num >> 4);
  752.   g_track_str[1] = '0' + (p_num & 15);
  753.   GT_SetGadgetAttrs (g_gadgets[GID_TRACK], g_window, NULL,
  754.              GTTX_Text, g_track_str, TAG_END);
  755.   g_track = p_num;
  756. }
  757.  
  758. void Update_Index_Data (short p_num)
  759. {
  760.   g_index_str[0] = '0' + (p_num >> 4);
  761.   g_index_str[1] = '0' + (p_num & 15);
  762.   GT_SetGadgetAttrs (g_gadgets[GID_INDEX], g_window, NULL,
  763.              GTTX_Text, g_index_str, TAG_END);
  764.   g_index = p_num;
  765. }
  766.  
  767. void Update_Time_Data (short p_min, short p_sec)
  768. {
  769.   g_time_str[0] = '0' + (p_min >> 4);
  770.   g_time_str[1] = '0' + (p_min & 15);
  771.   g_time_str[3] = '0' + (p_sec >> 4);
  772.   g_time_str[4] = '0' + (p_sec & 15);
  773.   GT_SetGadgetAttrs (g_gadgets[GID_TIME], g_window, NULL,
  774.              GTTX_Text, g_time_str, TAG_END);
  775.   g_minute = p_min;
  776.   g_seconds = p_sec;
  777. }
  778.  
  779. void Convert_Buffer (short p_phase)
  780. {
  781.   short i;
  782.   short sum;
  783.   BYTE *src = (BYTE *) g_cdda_buf[p_phase];
  784.   BYTE *dst = (BYTE *) g_audio_buf[p_phase];
  785.   BYTE *stop = src + (g_buffers * CDDA_BUFSIZE);
  786.   short skip = ((CDDA_BUFSIZE-SUBCHANNEL_SIZE)/4);
  787.   
  788.   while (src < stop) {
  789.     sum = 0;
  790.     for (i=0; i<g_compression_factor; i++) {
  791.       sum += src[1] + src[3];
  792.       src += 4;
  793.     }
  794.     for (i=g_volume-1; i--;)  /* this is faster than multiplication */
  795.       sum += sum;
  796.     sum /= (g_compression_factor << 1);
  797.     if (sum < -127)
  798.       sum = -127;
  799.     else if (sum > 127)
  800.       sum = 127;
  801.     *dst++ = sum;
  802.     skip -= g_compression_factor;
  803.     if (!skip) {
  804.       /* analyze Q-sub channel data: */
  805.       if (g_whatdrive == TOSHIBA) {
  806.     if (src[1] == 1) {
  807.       if (((UBYTE *) src)[2] != g_track)
  808.         Update_Track_Data (((UBYTE *) src)[2]);
  809.       if (((UBYTE *) src)[3] != g_index)
  810.         Update_Index_Data (((UBYTE *) src)[3]);
  811.       if (((UBYTE *) src)[5] != g_seconds ||
  812.           ((UBYTE *) src)[4] != g_minute)
  813.         Update_Time_Data (((UBYTE *) src)[4], ((UBYTE *) src)[5]);
  814.     }
  815.       }
  816.       else if (g_whatdrive == APPLECD300) {
  817.     if (src[0] == 1) {
  818.       if (((UBYTE *) src)[1] != g_track)
  819.         Update_Track_Data (((UBYTE *) src)[1]);
  820.       if (((UBYTE *) src)[2] != g_index)
  821.         Update_Index_Data (((UBYTE *) src)[2]);
  822.       if (((UBYTE *) src)[8] != g_seconds ||
  823.           ((UBYTE *) src)[7] != g_minute)
  824.         Update_Time_Data (((UBYTE *) src)[7], ((UBYTE *) src)[8]);
  825.     }
  826.       }
  827.       /* skip Q-sub channel data: */
  828.       src += SUBCHANNEL_SIZE;
  829.       skip = ((CDDA_BUFSIZE-SUBCHANNEL_SIZE)/4);
  830.     }
  831.   }
  832. }
  833.  
  834. void Start_Play_Audio (short p_phase)
  835. {
  836.   BeginIO ((struct IORequest *) (g_audioreq[p_phase]));
  837. }
  838.  
  839. void Wait_Play_Audio (short p_phase)
  840. {
  841.   ULONG sig;
  842.  
  843.   sig = Wait (SIGBREAKF_CTRL_C | g_audio_sigmask[p_phase]);
  844.   if (sig & g_audio_sigmask[p_phase]) {
  845.     while (GetMsg (g_audio_port[p_phase]) == 0) ;
  846.   }
  847.   if (sig & SIGBREAKF_CTRL_C)
  848.     exit (1);
  849. }
  850.  
  851. #define FORMAT_CDDA 0x82
  852. #define FORMAT_STD 0x00
  853.  
  854. void Select_Block_Format (int p_format)
  855. {
  856.   static UBYTE cmd[6] = { 0x15, 0x10, 0, 0, 12, 0 };
  857.   static UBYTE mode[12] = { 0, 0, 0, 8,
  858.                 0, 0, 0, 0, 0, 0, 0, 0 };
  859.  
  860.   mode[4] = p_format;
  861.   switch (p_format) {
  862.   case FORMAT_CDDA:
  863.     mode[10] = (CDDA_BUFSIZE >> 8);
  864.     mode[11] = (CDDA_BUFSIZE & 0xFF);
  865.     break;
  866.   case FORMAT_STD:
  867.     mode[10] = (STD_BUFSIZE >> 8);
  868.     mode[11] = (STD_BUFSIZE & 0xFF);
  869.     break;
  870.   }
  871.  
  872.   memcpy (g_cdda_std_buf, mode, sizeof (mode));
  873.   Do_SCSI_Command (cmd, 6, -1, TRUE, SCSIF_WRITE);
  874. }
  875.  
  876. void Read_Drive_Type (void)
  877. {
  878.   static UBYTE cmd[6] = { 0x12, 0, 0, 0, 0, 0};
  879.   static char *applecd300string = "SONY    CD-ROM CDU-8003";
  880.   static char *toshibastring = "TOSHIBA";
  881.   UBYTE *buf = g_cdda_std_buf;
  882.  
  883. #if STD_BUFSIZE > 255
  884.   cmd[4] = 0xff;
  885. #else
  886.   cmd[4] = STD_BUFSIZE & 0xff;
  887. #endif
  888.  
  889.   Do_SCSI_Command (cmd, 6, -1, TRUE, SCSIF_READ);
  890.  
  891.   if ((buf[0] & 0x1f) != 5)
  892.     Fatal_Error ("not a CD-ROM device\n");
  893.  
  894.   if (!memcmp(applecd300string,
  895.           &buf[8],
  896.           strlen(applecd300string))) {
  897.       g_whatdrive = APPLECD300;
  898.     }
  899.   else if (!memcmp(toshibastring,
  900.            &buf[8],
  901.            strlen(toshibastring))) {
  902.       g_whatdrive = TOSHIBA;
  903.     }
  904.   else
  905.     Fatal_Error ("unsupported CD-ROM drive\n");
  906. }
  907.  
  908. void Read_TOC (void)
  909. {
  910.   static UBYTE cmd[10] = { 0x43, 0, 0, 0, 0, 0, 1,
  911.                  STD_BUFSIZE >> 8, STD_BUFSIZE & 0xFF,
  912.                0, };
  913.   UBYTE *buf = g_cdda_std_buf;
  914.  
  915.   Do_SCSI_Command (cmd, 10, -1, TRUE, SCSIF_READ);
  916.   g_toc_length = ((buf[0] << 8) + buf[1] - 2) / 8;
  917.   memcpy (g_toc, buf + 4, 8 * g_toc_length);
  918. }
  919.  
  920. void Enable_Track_Buttons (void)
  921. {
  922.   int i, foo;
  923.  
  924.   for (i=0; i<g_toc_length; i++) {
  925.     /* ENFORCER HIT, because if () {statement} is executed, even
  926.      * though expression evalutes to 0 with SAS/C 6.50.
  927.      * (added foo to avoid problem <HR>)
  928.      */
  929.     foo = g_toc[i].track_number;
  930.     if (foo <= 20 &&
  931.         !(g_toc[i].flags & 4)) {
  932.       GT_SetGadgetAttrs (g_gadgets[g_toc[i].track_number],
  933.                    g_window, NULL,
  934.              GA_Disabled, FALSE,
  935.              TAG_END);
  936.     }
  937.   }
  938. }
  939.  
  940. long Track_Address (int p_track)
  941. {
  942.   int i;
  943.  
  944.   for (i=0; i<g_toc_length; i++) {
  945.     if (g_toc[i].track_number == p_track) {
  946.       if (g_toc[i].flags & 4)
  947.     return -1;
  948.       return g_toc[i].address;
  949.     }
  950.   }
  951.   return -1;
  952. }
  953.  
  954. int First_Track (void)
  955. {
  956.   int i;
  957.   
  958.   for (i=0; i<g_toc_length; i++) {
  959.     if (g_toc[i].track_number != 0xAA &&
  960.         !(g_toc[i].flags & 4))
  961.       return g_toc[i].track_number;
  962.   }
  963.   return 0;
  964. }
  965.  
  966. long Next_Track (int p_offset)
  967. {
  968.   int track = (g_track >> 4) * 10 + (g_track & 15);
  969.   long res;
  970.  
  971.   track += p_offset;
  972.   res = Track_Address (track);
  973.   return res == -1 ? Track_Address (track - p_offset) : res;
  974. }
  975.  
  976. void NTSC_or_PAL (void)
  977. {
  978.   if (GfxBase->DisplayFlags & PAL)
  979.     g_period = 3546895 / (44100 / g_compression_factor);
  980.   else
  981.     g_period = 3579545 / (44100 / g_compression_factor);
  982. }
  983.  
  984. void Init_Idle_Mode (void)
  985. {
  986.   GT_SetGadgetAttrs (g_gadgets[GID_STOP], g_window, NULL,
  987.              GA_Disabled, TRUE, TAG_END);
  988.   GT_SetGadgetAttrs (g_gadgets[GID_START], g_window, NULL,
  989.              GA_Disabled, FALSE, TAG_END);
  990.   GT_SetGadgetAttrs (g_gadgets[GID_SAMPLING_RATE], g_window, NULL,
  991.              GA_Disabled, FALSE, TAG_END);
  992.   GT_SetGadgetAttrs (g_gadgets[GID_BUFFERS], g_window, NULL,
  993.              GA_Disabled, FALSE, TAG_END);
  994.   GT_SetGadgetAttrs (g_gadgets[GID_PREV], g_window, NULL,
  995.              GA_Disabled, TRUE, TAG_END);
  996.   GT_SetGadgetAttrs (g_gadgets[GID_NEXT], g_window, NULL,
  997.              GA_Disabled, TRUE, TAG_END);
  998.   GT_SetGadgetAttrs (g_gadgets[GID_TRACK], g_window, NULL,
  999.                GTTX_Text, "", TAG_END);
  1000.   GT_SetGadgetAttrs (g_gadgets[GID_INDEX], g_window, NULL,
  1001.                GTTX_Text, "", TAG_END);
  1002.   GT_SetGadgetAttrs (g_gadgets[GID_TIME], g_window, NULL,
  1003.                GTTX_Text, "", TAG_END);
  1004. }
  1005.  
  1006. void Init_Play_Mode (void)
  1007. {
  1008.   GT_SetGadgetAttrs (g_gadgets[GID_STOP], g_window, NULL,
  1009.              GA_Disabled, FALSE, TAG_END);
  1010.   GT_SetGadgetAttrs (g_gadgets[GID_START], g_window, NULL,
  1011.              GA_Disabled, TRUE, TAG_END);
  1012.   GT_SetGadgetAttrs (g_gadgets[GID_SAMPLING_RATE], g_window, NULL,
  1013.              GA_Disabled, TRUE, TAG_END);
  1014.   GT_SetGadgetAttrs (g_gadgets[GID_BUFFERS], g_window, NULL,
  1015.              GA_Disabled, TRUE, TAG_END);
  1016.   GT_SetGadgetAttrs (g_gadgets[GID_PREV], g_window, NULL,
  1017.              GA_Disabled, FALSE, TAG_END);
  1018.   GT_SetGadgetAttrs (g_gadgets[GID_NEXT], g_window, NULL,
  1019.              GA_Disabled, FALSE, TAG_END);
  1020.   g_track = g_index = g_minute = g_seconds = 0xFF;
  1021. }
  1022.  
  1023. int Get_Intui_Message (long *p_sec_no)
  1024. {
  1025.   struct IntuiMessage *imsg;
  1026.   struct Gadget *gad;
  1027.   ULONG class;
  1028.   UWORD code;
  1029.  
  1030.   if (imsg = GT_GetIMsg (g_window->UserPort)) {
  1031.     class = imsg->Class;
  1032.     code = imsg->Code;
  1033.     gad = (struct Gadget *) imsg->IAddress;
  1034.     GT_ReplyIMsg (imsg);
  1035.     switch (class) {
  1036.     case IDCMP_CLOSEWINDOW: {
  1037.       g_bye = TRUE;
  1038.       return TRUE;
  1039.     }
  1040.     case IDCMP_GADGETUP:
  1041.       if (gad->GadgetID <= 20)
  1042.         *p_sec_no = Track_Address (gad->GadgetID);
  1043.       else if (gad->GadgetID == GID_STOP)
  1044.         return TRUE;
  1045.       else if (gad->GadgetID == GID_VOLUME)
  1046.         g_volume = code + 1;
  1047.       else if (gad->GadgetID == GID_PREV)
  1048.         *p_sec_no = Next_Track (-1);
  1049.       else if (gad->GadgetID == GID_NEXT)
  1050.         *p_sec_no = Next_Track (+1);
  1051.       break;
  1052.     default:
  1053.       break;
  1054.     }
  1055.   }
  1056.   return FALSE;
  1057. }
  1058.  
  1059. #define INC_SEC(ptr,inc) *(ptr) += (inc)
  1060.  
  1061. void main (int argc, char *argv[])
  1062. {
  1063.   short i=0;
  1064.   long sec_no;
  1065.   char *err;
  1066.   struct IntuiMessage *imsg;
  1067.   t_bool done;
  1068.   struct Gadget *gad;
  1069.   ULONG class;
  1070.   UWORD code;
  1071.   char *error_msg = NULL;
  1072.  
  1073.   atexit (Cleanup);
  1074.  
  1075.   g_called_from_cli = (argc > 0);
  1076.  
  1077.   if (g_called_from_cli) {
  1078.     static UBYTE* template = (UBYTE *)
  1079.                              "DEVICE/A,UNIT/A/N,CHIP/S,FAST/S,DMA/S,ANY/S,"
  1080.                      "LOW/S,MEDIUM/S,HIGH/S";
  1081.     enum Arg {
  1082.       ARG_DEVICE,
  1083.       ARG_UNIT,
  1084.       ARG_CHIP,
  1085.       ARG_FAST,
  1086.       ARG_DMA,
  1087.       ARG_ANY,
  1088.       ARG_LOW,
  1089.       ARG_MEDIUM,
  1090.       ARG_HIGH,
  1091.       ARGCOUNT
  1092.     };
  1093.     static LONG args[ARGCOUNT];
  1094.     struct RDArgs* rd;
  1095.     if (rd = ReadArgs (template, args, NULL)) {
  1096.       int cnt_mem = 0;
  1097.       int cnt_vol = 0;
  1098.       strcpy (g_scsi_device, (char*) (args[ARG_DEVICE]));
  1099.       g_scsi_id = args[ARG_UNIT];
  1100.       if (args[ARG_CHIP])
  1101.         g_memory_type = MEMF_CHIP, cnt_mem++;
  1102.       if (args[ARG_FAST])
  1103.         g_memory_type = MEMF_FAST, cnt_mem++;
  1104.       if (args[ARG_DMA])
  1105.         g_memory_type = MEMF_24BITDMA, cnt_mem++;
  1106.       if (args[ARG_ANY])
  1107.         g_memory_type = MEMF_ANY, cnt_mem++;
  1108.       if (args[ARG_LOW])
  1109.         g_volume = 1, cnt_vol++;
  1110.       if (args[ARG_MEDIUM])
  1111.         g_volume = 2, cnt_vol++;
  1112.       if (args[ARG_HIGH])
  1113.         g_volume = 3, cnt_vol++;
  1114.  
  1115.       FreeArgs (rd);
  1116.  
  1117.       if (cnt_mem > 1)
  1118.         Fatal_Error ("Only ONE memory option may be used!");
  1119.       if (cnt_vol > 1)
  1120.         Fatal_Error ("Only ONE volume option may be used!");
  1121.     } else
  1122.       Fatal_Error ("Args do not match template %s\n", template);
  1123.  
  1124.     strcpy (g_scsi_device, argv[1]);
  1125.     g_scsi_id = atoi (argv[2]);
  1126.   } else {
  1127.     char *str;
  1128.     UBYTE **toolarray;
  1129.     struct WBStartup *wbench_msg;
  1130.     struct DiskObject *dobj;
  1131.  
  1132.     if (!(IconBase = OpenLibrary ((UBYTE *) "icon.library", 37)))
  1133.       exit (1);
  1134.     wbench_msg = (struct WBStartup *) argv;
  1135.     dobj = GetDiskObject ((UBYTE *) wbench_msg->sm_ArgList->wa_Name);
  1136.     if (!dobj)
  1137.       exit (1);
  1138.     toolarray = (UBYTE **) dobj->do_ToolTypes;
  1139.     str = (char *) FindToolType (toolarray, (UBYTE *) "DEVICE");
  1140.     if (!str)
  1141.       error_msg = "Tool type DEVICE is missing";
  1142.     strcpy (g_scsi_device, str);
  1143.     str = (char *) FindToolType (toolarray, (UBYTE *) "UNIT");
  1144.     if (!str)
  1145.       error_msg = "Tool type UNIT is missing";
  1146.     g_scsi_id = atoi (str);
  1147.     str = (char *) FindToolType (toolarray, (UBYTE *) "MEMORY");
  1148.     if (str) {
  1149.       if (strcmp (str, "CHIP") == 0)
  1150.         g_memory_type = MEMF_CHIP;
  1151.       else if (strcmp (str, "FAST") == 0)
  1152.         g_memory_type = MEMF_FAST;
  1153.       else if (strcmp (str, "DMA") == 0)
  1154.         g_memory_type = MEMF_24BITDMA;
  1155.       else if (strcmp (str, "ANY") == 0)
  1156.         g_memory_type = MEMF_ANY;
  1157.       else
  1158.         error_msg = "Invalid MEMORY tool type";
  1159.     }
  1160.     str = (char *) FindToolType (toolarray, (UBYTE *) "VOLUME");
  1161.     if (str) {
  1162.       if (strcmp (str, "LOW") == 0)
  1163.         g_volume = 1;
  1164.       else if (strcmp (str, "MEDIUM") == 0)
  1165.         g_volume = 2;
  1166.       else if (strcmp (str, "HIGH") == 0)
  1167.         g_volume = 3;
  1168.       else
  1169.         error_msg = "Invalid VOLUME tool type";
  1170.     };
  1171.     FreeDiskObject (dobj);
  1172.   }
  1173.  
  1174.   err = Open_User_Interface ();
  1175.   if (err)
  1176.     Fatal_Error ("ERROR: %s", err);
  1177.  
  1178.   if (error_msg)
  1179.     Fatal_Error ("%s", error_msg);
  1180.  
  1181.   Alloc_CDROM ();
  1182.  
  1183.   Read_Drive_Type ();
  1184.  
  1185.   if (g_whatdrive == TOSHIBA)
  1186.     Select_Block_Format (FORMAT_CDDA);
  1187.  
  1188.   Read_TOC ();
  1189.  
  1190.   Enable_Track_Buttons ();
  1191.  
  1192.   if (!First_Track ())
  1193.     Fatal_Error ("This is no audio disk");
  1194.  
  1195.   while (!g_bye) {
  1196.  
  1197.     Init_Idle_Mode ();
  1198.  
  1199.     done = FALSE;
  1200.     while (!done) {
  1201.       Wait (1 << g_window->UserPort->mp_SigBit);
  1202.       while (imsg = GT_GetIMsg (g_window->UserPort)) {
  1203.         class = imsg->Class;
  1204.     code = imsg->Code;
  1205.         gad = (struct Gadget *) imsg->IAddress;
  1206.     GT_ReplyIMsg (imsg);
  1207.         switch (class) {
  1208.     case IDCMP_CLOSEWINDOW:
  1209.           Select_Block_Format (FORMAT_STD);  
  1210.       exit (0);
  1211.         case IDCMP_GADGETUP:
  1212.       if (gad->GadgetID <= 20) {
  1213.             sec_no = Track_Address (gad->GadgetID);
  1214.         done = TRUE;
  1215.       } else if (gad->GadgetID == GID_START) {
  1216.         sec_no = Track_Address (First_Track ());
  1217.         done = TRUE;
  1218.       } else if (gad->GadgetID == GID_VOLUME)
  1219.             g_volume = code + 1;
  1220.       else if (gad->GadgetID == GID_SAMPLING_RATE) {
  1221.         static short factors[] = { 2, 3, 4, 6, 7 };
  1222.         g_compression_factor = factors[code];
  1223.       } else if (gad->GadgetID == GID_BUFFERS) {
  1224.         static short buffers[] = { 2, 4, 8, 16, 32, 64 };
  1225.         g_buffers = buffers[code];
  1226.       }
  1227.           break;
  1228.         default:
  1229.           break;
  1230.         }
  1231.       }
  1232.     }
  1233.  
  1234.     Init_Play_Mode ();
  1235.  
  1236.     NTSC_or_PAL ();
  1237.     Alloc_Audio ();
  1238.  
  1239.     Start_CDROM_Read (0, sec_no);
  1240. #ifndef HRDBLBF
  1241.     Wait_CDROM_Read ();
  1242. #else
  1243.     Wait_CDROM_Read (0);
  1244. #endif
  1245.  
  1246.     INC_SEC (&sec_no, g_buffers);
  1247.     Start_CDROM_Read (1, sec_no);
  1248.     Convert_Buffer (0);
  1249. #ifndef HRDBLBF
  1250.     Wait_CDROM_Read ();
  1251. #else
  1252.     Wait_CDROM_Read (1);
  1253. #endif
  1254.     Convert_Buffer (1);
  1255.     Start_Play_Audio (0);
  1256.     Start_Play_Audio (1);
  1257.     INC_SEC (&sec_no, g_buffers);
  1258.     Start_CDROM_Read (0, sec_no);
  1259.  
  1260.     for (;;) {
  1261.       /* HERE: scsi-request i is active,
  1262.                play-audio i is active and
  1263.            play-audio 1-i is queued */
  1264.  
  1265.       if (Get_Intui_Message (&sec_no))
  1266.         break;
  1267. #ifndef HRDBLBF
  1268.       Wait_CDROM_Read ();
  1269. #else
  1270.       Wait_CDROM_Read (i);
  1271. #endif
  1272.       INC_SEC (&sec_no, g_buffers);
  1273.       Start_CDROM_Read (1-i, sec_no);
  1274.       Wait_Play_Audio (i);
  1275.       Convert_Buffer (i);
  1276.       Start_Play_Audio (i);
  1277.       i = 1-i;
  1278.     }
  1279.     
  1280. #ifndef HRDBLBF
  1281.     Wait_CDROM_Read ();
  1282. #else
  1283.     Wait_CDROM_Read (0);
  1284.     Wait_CDROM_Read (1);
  1285. #endif
  1286.     Wait_Play_Audio (i);
  1287.     Wait_Play_Audio (1-i);
  1288.     
  1289.     Cleanup_Audio ();
  1290.   }
  1291.  
  1292.   if (g_whatdrive == TOSHIBA)
  1293.     Select_Block_Format (FORMAT_STD);
  1294.  
  1295.   exit (0);
  1296. }
  1297.  
  1298.